林嶔 (Lin, Chin)
Lesson 19
– 機器學習的方法分為無監督學習法及監督學習法,我們的課程內容著重在監督學習法,其主要目標是想透過原始資料的特徵(feature),並經過模型進行預測(預測的outcome可以為連續或是類別)。
– 然而,有時候受限於研究的限制,我們沒有辦法將它們之間的關係描述得很精準,舉例來說,我們如何做手寫數字的辨識?
data(iris)
plot(iris[,1], iris[,2], col = as.factor(iris[,5]), pch = 19,
xlab = "Sepal Length", ylab = "Sepal Width")
– 事實上,這個套件做的是「Penalized」logistic regression。
#Split data
set.seed(0)
Train.sample = sample(1:150, 100, replace = FALSE)
Train.data = iris[Train.sample,]
Test.data = iris[-Train.sample,]
#Train a model
library(glmnet)
glm.model = glmnet(y = Train.data[,5],
x = as.matrix(Train.data[,1:4]),
family = "multinomial",
lambda = 0.1)
#Predict
pred.test = predict(glm.model, as.matrix(Test.data[,1:4]))
pred.y = max.col(pred.test[,,1])
#Comparision
table(pred.y, Test.data[,5])
##
## pred.y setosa versicolor virginica
## 1 18 0 0
## 2 0 14 1
## 3 0 1 16
– 其中第一欄是標籤,也就是0至9
– 第二欄開始是一個28*28圖片的像素,範圍大小是0-255
DAT = read.csv("data/train.csv")
#Split data
set.seed(0)
Train.sample = sample(1:nrow(DAT), nrow(DAT)*0.6, replace = FALSE)
Train.X = DAT[Train.sample,-1]
Train.Y = DAT[Train.sample,1]
Test.X = DAT[-Train.sample,-1]
Test.Y = DAT[-Train.sample,1]
#Display
library(imager)
par(mar=rep(0,4), mfcol = c(4, 4))
for (i in 1:16) {
plot(NA, xlim = 0:1, ylim = 0:1, xaxt = "n", yaxt = "n", bty = "n")
img = as.raster(t(matrix(as.numeric(Train.X[i,])/255, nrow = 28)))
rasterImage(img, -0.04, -0.04, 1.04, 1.04, interpolate=FALSE)
text(0.05, 0.95, Train.Y[i], col = "green", cex = 2)
}
– 使用Train.X與Train.Y建立模型,在以模型預測Test.X,並將預測結果與Test.Y進行比較
## Test.Y
## pred.y 0 1 2 3 4 5 6 7 8 9
## 1 1123 1 99 15 106 29 320 93 124 59
## 2 60 1819 385 1346 179 646 186 186 908 294
## 3 3 0 193 6 8 13 6 1 12 4
## 4 9 3 20 129 67 153 30 12 80 84
## 7 36 5 360 30 19 26 911 0 10 0
## 8 1 0 1 53 79 113 0 991 51 557
## 10 431 23 598 163 1148 571 208 470 490 644
## Training accuracy rate = 0.2122222
## Testing accuracy rate = 0.2145238
– 最簡單的監督機器學習法是決策樹,決策樹牽涉到了最少的數學,僅僅是使用電腦大量運算來進行分類。
data(iris)
#Split data
set.seed(0)
Train.sample = sample(1:150, 100, replace = FALSE)
Train.data = iris[Train.sample,]
Test.data = iris[-Train.sample,]
#Find optimal cut-points
optimal.cut_points = data.frame(var = colnames(Train.data)[1:4],
cut = numeric(4),
pval = numeric(4))
for (i in 1:4) {
unique.values = unique(sort(Train.data[,i]))
chisq.list = numeric(length(unique.values)-1)
for (j in 1:length(chisq.list)) {
potiantal.cut_points = (unique.values[j] + unique.values[j+1])/2
names(chisq.list)[j] = potiantal.cut_points
X = Train.data[,i] > potiantal.cut_points
Y = Train.data[,5]
chisq.list[j] = fisher.test(X, Y)$p.value
}
optimal.cut_points[i,2] = names(chisq.list)[which.min(chisq.list)]
optimal.cut_points[i,3] = min(chisq.list)
}
print(optimal.cut_points)
## var cut pval
## 1 Sepal.Length 5.55 7.257472e-16
## 2 Sepal.Width 3.15 2.248091e-09
## 3 Petal.Length 2.45 6.992396e-27
## 4 Petal.Width 0.8 6.992396e-27
library(party)
tree.model = ctree(formula = Species ~ ., data = Train.data)
plot(tree.model)
sort(Train.data[,3])
## [1] 1.2 1.2 1.3 1.3 1.3 1.3 1.3 1.4 1.4 1.4 1.4 1.4 1.4 1.4 1.4 1.4 1.5
## [18] 1.5 1.5 1.5 1.5 1.5 1.5 1.5 1.6 1.6 1.6 1.6 1.6 1.7 1.9 1.9 3.0 3.3
## [35] 3.3 3.5 3.6 3.7 3.8 3.9 3.9 4.0 4.0 4.0 4.1 4.1 4.2 4.2 4.2 4.3 4.4
## [52] 4.4 4.4 4.5 4.5 4.5 4.5 4.5 4.5 4.6 4.7 4.7 4.7 4.8 4.8 4.8 4.8 4.9
## [69] 4.9 5.0 5.0 5.0 5.1 5.1 5.1 5.2 5.2 5.3 5.3 5.4 5.4 5.5 5.5 5.6 5.6
## [86] 5.6 5.6 5.7 5.7 5.8 5.8 5.8 5.9 6.1 6.1 6.3 6.4 6.6 6.7 6.9
#Predict
pred.y = predict(tree.model, Test.data[,1:4])
#Comparision
table(pred.y, Test.data[,5])
##
## pred.y setosa versicolor virginica
## setosa 18 0 0
## versicolor 0 15 1
## virginica 0 0 16
– 想想決策樹的運算過程,你應該可以想像他要一陣子才能算完,你可能需要等2-3分鐘。
## Training accuracy rate = 0.7399206
## Testing accuracy rate = 0.7175595
## Test.Y
## pred.y2 0 1 2 3 4 5 6 7 8 9
## 0 1527 3 127 118 12 251 79 11 54 18
## 1 3 1535 29 41 18 33 13 92 50 26
## 2 14 135 1186 91 23 26 122 35 86 14
## 3 2 28 8 1006 6 119 5 7 11 14
## 4 2 1 15 10 979 10 42 18 10 14
## 5 31 4 19 172 54 691 23 42 101 150
## 6 37 5 115 12 41 56 1298 3 64 14
## 7 14 9 35 15 45 65 19 1353 21 86
## 8 15 107 72 77 50 68 38 29 1206 32
## 9 18 24 50 200 378 232 22 163 72 1274
– 但他有一個重要的缺陷,就是我們Training sample是一次抽樣的結果,而這個樣本一定存在了一些抽樣誤差造成的特色與母體未必相同,我們有沒有可能因為這個錯誤的特色導致了決策樹陷入「局部極值」?
– 接著,假設我們成功的製造了100棵小樹,要預測的時候就將這樣本經過這100棵樹,並請這100棵樹投票看看他們預測這個樣本的結果。
– 這樣的操作在數學上的意義,就像我們在做梯度下降法時從100個「隨機的起始點」開始疊代程序,即使我們無法判斷「全局極值」在哪個點,我們應該也能透過這100個方程式的投票獲得更準確的結果!
data(iris)
#Split data
set.seed(0)
Train.sample = sample(1:150, 100, replace = FALSE)
Train.data = iris[Train.sample,]
Test.data = iris[-Train.sample,]
#Load library
library(randomForest)
#Modeling
rf.model = randomForest(formula = Species ~ ., data = Train.data, ntree = 20)
#Predict
pred.y = predict(rf.model, Test.data)
table(pred.y, Test.data[,5])
##
## pred.y setosa versicolor virginica
## setosa 18 0 0
## versicolor 0 15 1
## virginica 0 0 16
– 僅僅20棵樹大約就花了2-3分鐘的時間計算,回家以後你可以設置多一點樹看看結果!
## Training accuracy rate = 0.9998413
## Testing accuracy rate = 0.9485119
## Test.Y
## pred.y2 0 1 2 3 4 5 6 7 8 9
## 0 1635 1 10 4 4 15 11 4 4 11
## 1 0 1821 3 3 4 0 4 8 12 4
## 2 1 5 1570 30 6 2 2 22 15 9
## 3 4 2 14 1616 0 40 1 2 31 24
## 4 0 3 10 2 1505 3 5 14 9 29
## 5 3 4 6 30 0 1446 11 1 25 12
## 6 9 3 10 2 15 17 1620 0 10 2
## 7 1 2 11 16 5 1 0 1665 5 26
## 8 10 8 19 24 15 17 7 8 1547 15
## 9 0 2 3 15 52 10 0 29 17 1510
– 但遺憾的是在訓練資料已經100%能預測,看來沒有上升空間了,但真的是這樣嗎?
本週我們帶領大家一起學會了決策樹及隨機森林,他們在面對一些較複雜的問題時效能遠遠超過了邏輯斯回歸。
儘管我們不清楚X與Y實際上的關係,這兩個機器學習的方法還是有效的協助我們預測出量的結果。
事實上,隨機森林還並非Tree-based model的最終型態,在2003年以後出現的梯度提升機(Gradient Boosting Machine)是一個比隨機森林更強的分類器
– 在R裡面最好用的套件是xgboost,如果你想深入學習請參考範例
– 他的概念是在建構樹的過程中改變樣本權重,使每一棵樹的變化性更大。
– 在Kaggle比賽中,使用xgboost建立的梯度提升機是各項賽事中的常勝軍,幾乎所有的比賽中都看的到他的身影。